package com.modifiertech.lineage.api;

import com.modifiertech.lineage.BaseConst;
import com.modifiertech.lineage.base.ConfigHandler;
import com.modifiertech.lineage.event.PlayerDataHandler;
import com.modifiertech.lineage.event.SkillAnimateCallEvent;
import com.modifiertech.lineage.event.SkillLevelUpEvent;
import com.modifiertech.lineage.event.SkillShortCutBindEvent;

import com.modifiertech.lineage.network.MessageClientSkillCD;
import com.modifiertech.lineage.network.MessageClientSkillHandingState;
import com.modifiertech.lineage.network.MessageClientSkillRange;
import com.modifiertech.lineage.network.NetworkHandler;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.*;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;

import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

public class PlayerData {
    public static String[] skillnamesordinary=new String[]{"reborn"};
    public static String[] skillnamesspecial=new String[]{"warrior_strengthFight"};
    public static String[] positive=new String[]{"haste"};
    public static String[] positivetemp=new String[]{"spriting"};

    public static String[] negative=new String[]{"slow"};
    public static String[] negativetemp=new String[]{"stun"};

    public static String[] rolebattle=new String[]{"warrior","archer","magican"};
    public static String[] roleordinary=new String[]{"farmer"};

    public static String[] title=new String[]{"zombieKiller","spiderMaster"};

    private final boolean client;
    public WeakReference<EntityPlayer> playerWR;
    //玩家属性NBT
    private PlayerDataAttributes playerDataAttributes=new PlayerDataAttributes();
    //玩家技能NBT
    private PlayerDataSkills playerDataSkills=new PlayerDataSkills();
    //玩家角色NBT
    private PlayerDataRoleTag playerDataRoleTag=new PlayerDataRoleTag();
    //增益标签NBT
    private PlayerDataPositiveTag playerDataPositiveTag=new PlayerDataPositiveTag();
    //减益标签NBT
    private PlayerDataNegativeTag playerDataNegativeTag=new PlayerDataNegativeTag();
    //称号标签NBT
    private PlayerDataTitleTag playerDataTitleTag=new PlayerDataTitleTag();
    //等级标签NBT
    private PlayerDataLevelTag playerDataLevelTag=new PlayerDataLevelTag();
    //玩家技能快捷键NBT
    private PlayerDataShortCutTag playerDataShortCutTag = new PlayerDataShortCutTag();
    //玩家技能执行临时缓存
    private PlayerExecuteSkillCache playerExecuteSkillCache = new PlayerExecuteSkillCache();
    //魔力标签NBT
    private PlayerDataManaTag playerDataManaTag=new PlayerDataManaTag();

    public PlayerData(EntityPlayer player){
        playerWR=new WeakReference<>(player);

        client=player.getEntityWorld().isRemote;
        load();
    }

    /**load取NBT信息
     *
     */
    public void load() {
        if (!client) {
            EntityPlayer player = playerWR.get();
            if (player != null) {
                NBTTagCompound cmp = PlayerDataHandler.getDataCompoundForPlayer(player);
                loadFromNBT(cmp);
            }
        }
    }

    /**保存NBT信息
     *
     */
    public synchronized void save() {
        if (!client) {
            EntityPlayer player = playerWR.get();
            if (player != null) {
                NBTTagCompound cmp = PlayerDataHandler.getDataCompoundForPlayer(player);
                saveToNBT(cmp);
            }
        }
    }

    /**同步NBT信息
     *
     */
    public synchronized void sync() {
        if (!client) {
            EntityPlayer player = playerWR.get();
            LineageAPI.getInstance().syncPlayerData(player, this);
        }
    }

    public synchronized void saveAndSync() {
        save();//存入服务端ForgeData里用户
        sync();
    }
    public synchronized void saveAndSyncSilent() {
        save();
        sync();
    }

    /**将数据从NBT数据存至本地用户信息数据
     *
     * @param cmp
     */
    public void loadFromNBT(NBTTagCompound cmp) {
        NBTTagCompound lineageNbtTagCompound = cmp;
        //attributes===============================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG__ATTR)){

            playerDataAttributes.setUndistributed(lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ATTR).getInteger(BaseConst.Attr.UnDistribute.name()));
            playerDataAttributes.setStrength(lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ATTR).getInteger(BaseConst.Attr.Strength.name()));
            playerDataAttributes.setAgile(lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ATTR).getInteger(BaseConst.Attr.Agile.name()));
            playerDataAttributes.setPhysique(lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ATTR).getInteger(BaseConst.Attr.Physique.name()));
            playerDataAttributes.setIntelligence(lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ATTR).getInteger(BaseConst.Attr.Intelligence.name()));
        }
        //skills=============================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG__SKILLS)){
            NBTTagCompound nbtTagCompoundSkill=lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS);
            //ordinary
            if(nbtTagCompoundSkill.hasKey(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD)){
                ConcurrentHashMap<String,PlayerDataSkill> tempOrdinary=new ConcurrentHashMap<>();
                for(String name:nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD).getKeySet()){
                        PlayerDataSkill playerDataSkill= playerDataSkills.getSkillInstanceFromAll(name).get();
                        playerDataSkill.setSkillLevel(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD).getCompoundTag(name).getInteger(BaseConst.PLAYER_ADV_TAG__SKILL_LVL));
                        playerDataSkill.setSkillName(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD).getCompoundTag(name).getString(BaseConst.PLAYER_ADV_TAG__SKILL_NAME));
                        playerDataSkill.setSkillType(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD).getCompoundTag(name).getString(BaseConst.PLAYER_ADV_TAG__SKILL_TYPE));
                        playerDataSkill.setEnable(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD).getCompoundTag(name).getBoolean(BaseConst.PLAYER_BASE_ENABLE));
                        playerDataSkill.setCoolDown(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD).getCompoundTag(name).getInteger(BaseConst.PLAYER_BASE_COOLDOWN));
                    tempOrdinary.put(name,playerDataSkill);
                }
                playerDataSkills.setOrdinarySkillMapping(tempOrdinary);
            }
            //special
            if(nbtTagCompoundSkill.hasKey(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE)){
                ConcurrentHashMap<String,PlayerDataSkill> tempSpecial=new ConcurrentHashMap<>();
                for(String name:nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE).getKeySet()){
                    PlayerDataSkill playerDataSkill= playerDataSkills.getSkillInstanceFromAll(name).get();
                        playerDataSkill.setSkillLevel(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE).getCompoundTag(name).getInteger(BaseConst.PLAYER_ADV_TAG__SKILL_LVL));
                        playerDataSkill.setSkillName(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE).getCompoundTag(name).getString(BaseConst.PLAYER_ADV_TAG__SKILL_NAME));
                        playerDataSkill.setSkillType(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE).getCompoundTag(name).getString(BaseConst.PLAYER_ADV_TAG__SKILL_TYPE));
                        playerDataSkill.setEnable(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE).getCompoundTag(name).getBoolean(BaseConst.PLAYER_BASE_ENABLE));
                        playerDataSkill.setCoolDown(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE).getCompoundTag(name).getInteger(BaseConst.PLAYER_BASE_COOLDOWN));
                    tempSpecial.put(name,playerDataSkill);
                }
                playerDataSkills.setSpecialSkillMapping(tempSpecial);
            }
            //points 技能点数
            if(nbtTagCompoundSkill.hasKey(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT)){
                //总技能点数
                playerDataSkills.setTotalSkillPoint(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT).getInteger(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT_TOTAL));
                //未分配技能点数
                playerDataSkills.setUndistributedSkillPoint(nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT).getInteger(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT_UNDISTRIBUTE));
            }
            //shortcut 快捷键绑定
            if(nbtTagCompoundSkill.hasKey(BaseConst.PLAYER_ADV_TAG__SKILLS_SHORTCUT)){
                ConcurrentHashMap<String,PlayerDataSkill> tempSkillRel=new ConcurrentHashMap<>();
                //存储规则:快捷键ID::技能，例: '0::StrongAsBull'
                for(String define:nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SHORTCUT).getKeySet()){

                    String shortId = define;
                    String skillName = nbtTagCompoundSkill.getCompoundTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SHORTCUT)
                            .getString(define);
                    //通过技能名获取技能实例
                    if (playerDataSkills.getSkillInstance(skillName).isPresent()){
                        PlayerDataSkill playerDataSkill = playerDataSkills.getSkillInstance(skillName).get();
                        tempSkillRel.put(shortId,playerDataSkill);
                    }
                }
                playerDataShortCutTag.setShortCutRelSkill(tempSkillRel);
            }
        }
        //roletags======================================================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG__ROLE)){
            NBTTagCompound nbtTagCompoundRole=lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ROLE);
            //battlerole
            if(nbtTagCompoundRole.hasKey(BaseConst.PLAYER_ADV_TAG__ROLE_BATTLEROLETAGS)){
                ConcurrentHashMap<String,PlayerDataTagItem> rolebattletemp=new ConcurrentHashMap<>();
                for(String name:nbtTagCompoundRole.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ROLE_BATTLEROLETAGS).getKeySet()){
                        PlayerDataTagItem playerDataItem=new PlayerDataTagItem();
                        playerDataItem.setTagName(name);
                        rolebattletemp.put(name,playerDataItem);
                }
                playerDataRoleTag.setBattleRoleTag(rolebattletemp);
            }
            //ordinaryrole
            if(nbtTagCompoundRole.hasKey(BaseConst.PLAYER_ADV_TAG__ROLE_ORDINGNARYROLETAGS)){
                ConcurrentHashMap<String,PlayerDataTagItem> rolebattleord=new ConcurrentHashMap<>();
                for(String name:nbtTagCompoundRole.getCompoundTag(BaseConst.PLAYER_ADV_TAG__ROLE_ORDINGNARYROLETAGS).getKeySet()){
                        PlayerDataTagItem playerDataItem=new PlayerDataTagItem();
                        playerDataItem.setTagName(name);
                        rolebattleord.put(name,playerDataItem);
                }
                playerDataRoleTag.setOrdinaryRoleTag(rolebattleord);
            }
        }
        //positivetags================================================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG_POSITIVETAG)){
            NBTTagCompound nbtTagCompoundpositive=lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG_POSITIVETAG);
            //temp
            if(nbtTagCompoundpositive.hasKey(BaseConst.PLAYER_BASE_TAG_TEMP)) {
                ConcurrentHashMap<String, PlayerDataTagItem> positivetemptemp = new ConcurrentHashMap<>();
                for (String name : nbtTagCompoundpositive.getCompoundTag(BaseConst.PLAYER_BASE_TAG_TEMP).getKeySet()) {
                        PlayerDataTagItem playerDataItem = new PlayerDataTagItem();
                        playerDataItem.setTagName(name);
                        playerDataItem.setTagDuarition(nbtTagCompoundpositive.getCompoundTag(BaseConst.PLAYER_BASE_TAG_TEMP).getLong(BaseConst.PLAYER_BASE_TAGDUARITION));
                        playerDataItem.setTagValue(nbtTagCompoundpositive.getCompoundTag(BaseConst.PLAYER_BASE_TAG_TEMP).getInteger(BaseConst.PLAYER_BASE_TAGVALUE));
                        positivetemptemp.put(name, playerDataItem);
                }
                playerDataPositiveTag.setTemporaryPositiveTags(positivetemptemp);
            }
                //persistent
            if(nbtTagCompoundpositive.hasKey(BaseConst.PLAYER_BASE_TAG_PRESIS)) {
                ConcurrentHashMap<String, PlayerDataTagItem> positivepersistemp = new ConcurrentHashMap<>();
                for (String name : nbtTagCompoundpositive.getCompoundTag(BaseConst.PLAYER_BASE_TAG_PRESIS).getKeySet()) {
                        PlayerDataTagItem playerDataItem = new PlayerDataTagItem();
                        playerDataItem.setTagName(name);
                    positivepersistemp.put(name, playerDataItem);
                }
                playerDataPositiveTag.setPersistentPositiveTags(positivepersistemp);
            }
        }
        //negativetags===========================================================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG_NEGATIVETAG)){
            NBTTagCompound nbtTagCompoundnegative=lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG_NEGATIVETAG);
            //temp
            if(nbtTagCompoundnegative.hasKey(BaseConst.PLAYER_BASE_TAG_TEMP)) {
                ConcurrentHashMap<String, PlayerDataTagItem> nagativetemptemp = new ConcurrentHashMap<>();
                for (String name : nbtTagCompoundnegative.getCompoundTag(BaseConst.PLAYER_BASE_TAG_TEMP).getKeySet()) {
                    PlayerDataTagItem playerDataItem = new PlayerDataTagItem();
                    playerDataItem.setTagName(name);
                    playerDataItem.setTagDuarition(nbtTagCompoundnegative.getCompoundTag(BaseConst.PLAYER_BASE_TAG_TEMP).getLong(BaseConst.PLAYER_BASE_TAGDUARITION));
                    playerDataItem.setTagValue(nbtTagCompoundnegative.getCompoundTag(BaseConst.PLAYER_BASE_TAG_TEMP).getInteger(BaseConst.PLAYER_BASE_TAGVALUE));
                    nagativetemptemp.put(name, playerDataItem);
                }
                playerDataNegativeTag.setTemporaryNegativeTags(nagativetemptemp);
            }
            //persistent
            if(nbtTagCompoundnegative.hasKey(BaseConst.PLAYER_BASE_TAG_PRESIS)) {
                ConcurrentHashMap<String, PlayerDataTagItem> positivepersistemp = new ConcurrentHashMap<>();
                for (String name : nbtTagCompoundnegative.getCompoundTag(BaseConst.PLAYER_BASE_TAG_PRESIS).getKeySet()) {
                    PlayerDataTagItem playerDataItem = new PlayerDataTagItem();
                    playerDataItem.setTagName(name);
                    positivepersistemp.put(name, playerDataItem);
                }
                playerDataNegativeTag.setPersistentNegativeTags(positivepersistemp);
            }
        }
        //titletags=========================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG_TITLETAGS)){
           NBTTagCompound titlecompound =lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG_TITLETAGS);
            ConcurrentHashMap<String, PlayerDataTagItem> titletagstemp = new ConcurrentHashMap<>();
            for(String name :titlecompound.getKeySet()){
                PlayerDataTagItem playerDataTagItem=new PlayerDataTagItem();
                playerDataTagItem.setTagName(name);
                titletagstemp.put(name,playerDataTagItem);
            }
            playerDataTitleTag.setTitleTags(titletagstemp);
        }
        //人物等级相关nbt标签
        //leveltags========================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG_LVLTAG)){
            NBTTagCompound levelcompound =lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG_LVLTAG);
            playerDataLevelTag.setCurrentExp(levelcompound.getLong(BaseConst.PLAYER_ADV_TAG_LVLTAG_EXP));
            playerDataLevelTag.setCurrentLevel(levelcompound.getLong(BaseConst.PLAYER_ADV_TAG_LVLTAG_LEVEL));
            playerDataLevelTag.setCurrentMaxExp(levelcompound.getLong(BaseConst.PLAYER_ADV_TAG_LVLTAG_EXP_MAX));
        }
        //魔力相关nbt标签
        //manatags=========================================================
        if(lineageNbtTagCompound.hasKey(BaseConst.PLAYER_ADV_TAG_MANATAG)){
            NBTTagCompound manacompound =lineageNbtTagCompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG_MANATAG);
            playerDataManaTag.setMaxMana(manacompound.getDouble(BaseConst.PLAYER_ADV_TAG_MANATAG_MAXMANA));
            playerDataManaTag.setCurrentMana(manacompound.getDouble(BaseConst.PLAYER_ADV_TAG_MANATAG_CURRENTMANA));
            playerDataManaTag.setRecoveryOfMana(manacompound.getDouble(BaseConst.PLAYER_ADV_TAG_MANATAG_MANARECOVER));
            NBTTagCompound manamod =manacompound.getCompoundTag(BaseConst.PLAYER_ADV_TAG_MANATAG_MODIFIER);
            ConcurrentHashMap<String, Double> manaModifier = new ConcurrentHashMap<>();
            for (String modifier : manamod.getKeySet()) {
                manaModifier.put(modifier,manamod.getDouble(modifier));
            }
            playerDataManaTag.setManaModifierMap(manaModifier);
        }

    }

    /**玩家魔法值修饰器更新
     * 重算当前最大魔法值
     */
    public void manaDataUpdate(){
        double total =ConfigHandler.attrManaBasic;
        //重算modifier
        for (Map.Entry<String, Double> stringDoubleEntry : playerDataManaTag.getManaModifierMap().entrySet()) {
            total+= stringDoubleEntry.getValue();
        }
        if (total<0)total = 0;
        //修正溢出
        double current = playerDataManaTag.getCurrentMana();
        if (current>total)current = total;
        playerDataManaTag.setMaxMana(total);
        playerDataManaTag.setCurrentMana(current);
    }

    /**魔法修饰更新
     *
     * @param modifierName
     * @param modifierValue
     */
    public void manaModifierUpdate(String modifierName,Double modifierValue){
        playerDataManaTag.getManaModifierMap().put(modifierName,modifierValue);
    }


    /**将数据从本地数据存至对应数据节点
     *
     * @param cmp
     */
    public synchronized void saveToNBT(NBTTagCompound cmp) {
        NBTTagCompound root = cmp;
        //LEVEL
        NBTTagCompound level=new NBTTagCompound();
        level.setLong(BaseConst.PLAYER_ADV_TAG_LVLTAG_LEVEL,playerDataLevelTag.getCurrentLevel());
        level.setLong(BaseConst.PLAYER_ADV_TAG_LVLTAG_EXP,playerDataLevelTag.getCurrentExp());
        level.setLong(BaseConst.PLAYER_ADV_TAG_LVLTAG_EXP_MAX,playerDataLevelTag.getCurrentMaxExp());
        root.setTag(BaseConst.PLAYER_ADV_TAG_LVLTAG,level);
        //MANA
        NBTTagCompound mana=new NBTTagCompound();
        mana.setDouble(BaseConst.PLAYER_ADV_TAG_MANATAG_CURRENTMANA,playerDataManaTag.getCurrentMana());
        mana.setDouble(BaseConst.PLAYER_ADV_TAG_MANATAG_MAXMANA,playerDataManaTag.getMaxMana());
        mana.setDouble(BaseConst.PLAYER_ADV_TAG_MANATAG_MANARECOVER,playerDataManaTag.getRecoveryOfMana());
        //MANA MODIFIER
        NBTTagCompound manamodifier=new NBTTagCompound();
        for (Map.Entry<String, Double> stringDoubleEntry : playerDataManaTag.getManaModifierMap().entrySet()) {
            manamodifier.setDouble(stringDoubleEntry.getKey(),stringDoubleEntry.getValue());
        }
        mana.setTag(BaseConst.PLAYER_ADV_TAG_MANATAG_MODIFIER,manamodifier);
        root.setTag(BaseConst.PLAYER_ADV_TAG_MANATAG,mana);

        //ATTRIBUTE
        NBTTagCompound attr=new NBTTagCompound();
        attr.setInteger(BaseConst.Attr.Strength.name(),playerDataAttributes.getStrength());
        attr.setInteger(BaseConst.Attr.UnDistribute.name(),playerDataAttributes.getUndistributed());
        attr.setInteger(BaseConst.Attr.Agile.name(),playerDataAttributes.getAgile());
        attr.setInteger(BaseConst.Attr.Physique.name(),playerDataAttributes.getPhysique());
        attr.setInteger(BaseConst.Attr.Intelligence.name(),playerDataAttributes.getIntelligence());
        root.setTag(BaseConst.PLAYER_ADV_TAG__ATTR,attr);
        //SKILLS
        NBTTagCompound skill=new NBTTagCompound();
        //普通技能,回写NBT
        NBTTagCompound skillord=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataSkill> entry: playerDataSkills.getOrdinarySkillMapping().entrySet()){
            NBTTagCompound skillordsingle=new NBTTagCompound();
            skillordsingle.setInteger(BaseConst.PLAYER_ADV_TAG__SKILL_LVL,entry.getValue().getSkillLevel());
            skillordsingle.setInteger(BaseConst.PLAYER_BASE_COOLDOWN,entry.getValue().getCoolDown());
            skillordsingle.setString(BaseConst.PLAYER_ADV_TAG__SKILL_TYPE,entry.getValue().getSkillType());
            skillordsingle.setString(BaseConst.PLAYER_ADV_TAG__SKILL_NAME,entry.getValue().getSkillName());
            skillordsingle.setBoolean(BaseConst.PLAYER_BASE_ENABLE,entry.getValue().isEnable());
            skillord.setTag(entry.getKey(),skillordsingle);
        }
        //特殊技能,回写NBT
        NBTTagCompound skillspe=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataSkill> entry: playerDataSkills.getSpecialSkillMapping().entrySet()){
            NBTTagCompound skillspesingle=new NBTTagCompound();
            skillspesingle.setInteger(BaseConst.PLAYER_ADV_TAG__SKILL_LVL,entry.getValue().getSkillLevel());
            skillspesingle.setInteger(BaseConst.PLAYER_BASE_COOLDOWN,entry.getValue().getCoolDown());
            skillspesingle.setString(BaseConst.PLAYER_ADV_TAG__SKILL_TYPE,entry.getValue().getSkillType());
            skillspesingle.setString(BaseConst.PLAYER_ADV_TAG__SKILL_NAME,entry.getValue().getSkillName());
            skillspesingle.setBoolean(BaseConst.PLAYER_BASE_ENABLE,entry.getValue().isEnable());
            skillspe.setTag(entry.getKey(),skillspesingle);
        }
        //技能点,回写NBT
        NBTTagCompound skillPoint=new NBTTagCompound();
        skillPoint.setInteger(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT_TOTAL,playerDataSkills.getTotalSkillPoint());
        skillPoint.setInteger(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT_UNDISTRIBUTE,playerDataSkills.getUndistributedSkillPoint());
        //技能快捷键,回写NBT
        NBTTagCompound skillShortCut=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataSkill> entry: playerDataShortCutTag.getShortCutRelSkill().entrySet()){
            skillShortCut.setString(entry.getKey(),entry.getValue().getSkillName());
        }


        skill.setTag(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD,skillord);
        skill.setTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE,skillspe);
        skill.setTag(BaseConst.PLAYER_ADV_TAG__SKILLS_POINT,skillPoint);
        skill.setTag(BaseConst.PLAYER_ADV_TAG__SKILLS_SHORTCUT,skillShortCut);

        root.setTag(BaseConst.PLAYER_ADV_TAG__SKILLS,skill);
        //ROLETAG
        NBTTagCompound role=new NBTTagCompound();
        NBTTagCompound roleord=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataRoleTag.getOrdinaryRoleTag().entrySet()){
            NBTTagCompound roleordsingle=new NBTTagCompound();
            roleordsingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());//rolestage
            roleord.setTag(entry.getKey(),roleordsingle);
        }
        role.setTag(BaseConst.PLAYER_ADV_TAG__ROLE_ORDINGNARYROLETAGS,roleord);
        NBTTagCompound rolebat=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataRoleTag.getBattleRoleTag().entrySet()){
            NBTTagCompound rolebatsingle=new NBTTagCompound();
            rolebatsingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());//rolestage
            rolebat.setTag(entry.getKey(),rolebatsingle);
        }
        role.setTag(BaseConst.PLAYER_ADV_TAG__ROLE_BATTLEROLETAGS,rolebat);
        root.setTag(BaseConst.PLAYER_ADV_TAG__ROLE,role);
        //POSITIVE
        NBTTagCompound positive=new NBTTagCompound();
        NBTTagCompound positivetemp=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataPositiveTag.getTemporaryPositiveTags().entrySet()){
            NBTTagCompound positivetempsingle=new NBTTagCompound();
            positivetempsingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());
            positivetempsingle.setLong(BaseConst.PLAYER_BASE_TAGDUARITION,entry.getValue().getTagDuarition());
            positivetemp.setTag(entry.getKey(),positivetempsingle);
        }
        positive.setTag(BaseConst.PLAYER_BASE_TAG_TEMP,positivetemp);
        NBTTagCompound positivepersis=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataPositiveTag.getPersistentPositiveTags().entrySet()){
            NBTTagCompound positivepersissingle=new NBTTagCompound();
            positivepersissingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());
            positivepersissingle.setLong(BaseConst.PLAYER_BASE_TAGDUARITION,entry.getValue().getTagDuarition());
            positivepersis.setTag(entry.getKey(),positivepersissingle);
        }
        positive.setTag(BaseConst.PLAYER_BASE_TAG_PRESIS,positivepersis);
        root.setTag(BaseConst.PLAYER_ADV_TAG_POSITIVETAG,positive);

        //NEGATIVE
        NBTTagCompound negative=new NBTTagCompound();
        NBTTagCompound negativetemp=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataNegativeTag.getTemporaryNegativeTags().entrySet()){
            NBTTagCompound negativetempsingle=new NBTTagCompound();
            negativetempsingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());
            negativetempsingle.setLong(BaseConst.PLAYER_BASE_TAGDUARITION,entry.getValue().getTagDuarition());
            negativetemp.setTag(entry.getKey(),negativetempsingle);
        }
        negative.setTag(BaseConst.PLAYER_BASE_TAG_TEMP,negativetemp);
        NBTTagCompound negativepresis=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataNegativeTag.getPersistentNegativeTags().entrySet()){
            NBTTagCompound negativepresispersissingle=new NBTTagCompound();
            negativepresispersissingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());
            negativepresispersissingle.setLong(BaseConst.PLAYER_BASE_TAGDUARITION,entry.getValue().getTagDuarition());
            negativepresis.setTag(entry.getKey(),negativepresispersissingle);
        }
        negative.setTag(BaseConst.PLAYER_BASE_TAG_PRESIS,negativepresis);
        root.setTag(BaseConst.PLAYER_ADV_TAG_NEGATIVETAG,negative);
        //TITLE
        NBTTagCompound title=new NBTTagCompound();
        for(Map.Entry<String,PlayerDataTagItem> entry: playerDataTitleTag.getTitleTags().entrySet()){
            NBTTagCompound titlesingle=new NBTTagCompound();
            titlesingle.setInteger(BaseConst.PLAYER_BASE_TAGVALUE,entry.getValue().getTagValue());
            title.setTag(entry.getKey(),titlesingle);
        }
        root.setTag(BaseConst.PLAYER_ADV_TAG_TITLETAGS,title);
    }

    /**操作属性
     *
     * @param attrname
     * @param opttype
     * @param optvalue
     */
    public synchronized void optAttr(String attrname,String opttype,int optvalue){
        if(attrname.equals(BaseConst.Attr.Strength.name())){
            if (opttype.equals(BaseConst.AttrOperate.add.name())){
                playerDataAttributes.setStrength(playerDataAttributes.getStrength()+optvalue);
            }else if(opttype.equals(BaseConst.AttrOperate.sub.name())){
                playerDataAttributes.setStrength(playerDataAttributes.getStrength()-optvalue);
            }else if(opttype.equals(BaseConst.AttrOperate.clear.name())){
                playerDataAttributes.setStrength(0);
            }else{}
            return;
        }
        if(attrname.equals(BaseConst.Attr.Agile.name())){
            if (opttype.equals(BaseConst.AttrOperate.add.name())){
                playerDataAttributes.setAgile(playerDataAttributes.getAgile()+optvalue);
            }else if(opttype.equals(BaseConst.AttrOperate.sub.name())){
                playerDataAttributes.setAgile(playerDataAttributes.getAgile()-optvalue);
            }else if(opttype.equals(BaseConst.AttrOperate.clear.name())){
                playerDataAttributes.setAgile(0);
            }else{}
            return;
        }
        if(attrname.equals(BaseConst.Attr.Physique.name())){
            if (opttype.equals(BaseConst.AttrOperate.add.name())){
                playerDataAttributes.setPhysique(playerDataAttributes.getPhysique()+optvalue);
            }else if(opttype.equals(BaseConst.AttrOperate.sub.name())){
                playerDataAttributes.setPhysique(playerDataAttributes.getPhysique()-optvalue);
            }else if(opttype.equals(BaseConst.AttrOperate.clear.name())){
                playerDataAttributes.setPhysique(0);
            }else{}
            return;
        }
        if(attrname.equals(BaseConst.Attr.Intelligence.name())) {
            if (opttype.equals(BaseConst.AttrOperate.add.name())) {
                playerDataAttributes.setIntelligence(playerDataAttributes.getIntelligence() + optvalue);
            } else if (opttype.equals(BaseConst.AttrOperate.sub.name())) {
                playerDataAttributes.setIntelligence(playerDataAttributes.getIntelligence() - optvalue);
            } else if (opttype.equals(BaseConst.AttrOperate.clear.name())) {
                playerDataAttributes.setIntelligence(0);
            } else {
            }
        }
            if(attrname.equals(BaseConst.Attr.UnDistribute.name())){
                if (opttype.equals(BaseConst.AttrOperate.add.name())){
                    playerDataAttributes.setUndistributed(playerDataAttributes.getUndistributed()+optvalue);
                }else if(opttype.equals(BaseConst.AttrOperate.sub.name())){
                    playerDataAttributes.setUndistributed(playerDataAttributes.getUndistributed()-optvalue);
                }else if(opttype.equals(BaseConst.AttrOperate.clear.name())){
                    playerDataAttributes.setUndistributed(0);
                }else{}
        }
        return;

    }

    public int getAttr(String attrname){
        if(BaseConst.Attr.Strength.name().equals(attrname)){
            return playerDataAttributes.getStrength();
        }else if(BaseConst.Attr.Agile.name().equals(attrname)){
            return playerDataAttributes.getAgile();
        }else if(BaseConst.Attr.Intelligence.name().equals(attrname)){
            return playerDataAttributes.getIntelligence();
        }else if(BaseConst.Attr.Physique.name().equals(attrname)){
            return playerDataAttributes.getPhysique();
        }else if(BaseConst.Attr.UnDistribute.name().equals(attrname)){
            return playerDataAttributes.getUndistributed();
        } else{
            return 0;
        }
    }

    public int getSkillPointTotal(){
        return playerDataSkills.getTotalSkillPoint();
    }
    public int getSkillPointUndistributed(){
        return playerDataSkills.getUndistributedSkillPoint();
    }


    public synchronized void subSkillUndistributed(int subNumber, String skillName){
        //扣减技能点 = 技能等级* 每级消耗的技能点数
        int point = subNumber*(getPlayerDataSkillByName(skillName).get().getUpgradeCount());
        playerDataSkills.setUndistributedSkillPoint(
                playerDataSkills.getUndistributedSkillPoint()-point
        );
    }
    /**查看是否满足技能条件
     *
     * @param skillName
     * @return
     */
    public boolean sureSkillAvailable(String skillName){
        if(null==skillName)return false;
        if(0==skillName.trim().length())return false;
        String[] skillParams=skillName.split(":");
        String skillname=skillParams[0];
        Integer skillLevel=skillParams.length>1?Integer.parseInt(skillParams[1]):null;
        if(playerDataSkills.getOrdinarySkillMapping().containsKey(skillname)&& playerDataSkills.getOrdinarySkillMapping().get(skillname).isEnable()){
            if(null!=skillLevel&& playerDataSkills.getOrdinarySkillMapping().get(skillname).getSkillLevel()<skillLevel){
                return false;
            }else{
                return true;
            }
        }
        if(playerDataSkills.getSpecialSkillMapping().containsKey(skillname)&& playerDataSkills.getSpecialSkillMapping().get(skillname).isEnable()){
            if(null!=skillLevel&& playerDataSkills.getSpecialSkillMapping().get(skillname).getSkillLevel()<skillLevel){
                return false;
            }else{
                return true;
            }
        }
        return false;
    }


    /**获取技能范围合法状态
     * @return
     */
    public boolean getSkillRangeAvailableStatus() {
        return playerExecuteSkillCache.isSkillRangeAvailable();
    }


    /**修改技能范围合法状态
     * 
     * @param status
     */
    public void updateSkillRangeAvailableStatus(boolean status) {
    	playerExecuteSkillCache.setSkillRangeAvailable(status);
    }

    /**修改技能范围合法状态:带客户端同步
     *
     * @param status
     */
    public void updateSkillRangeAvailableStatusAndSync(boolean status, EntityPlayerMP entityPlayerMP) {
        updateSkillRangeAvailableStatus(status);
        NetworkHandler.INSTANCE.sendTo(new MessageClientSkillRange().writeStatus(status),entityPlayerMP);
    }


    /**获取当前AABB盒子内实体
     * 
     * @param serverWorld
     * @return
     */
    public Set<Entity> getEntityFromAABBSkillRange(World serverWorld){
    	//
    	Set<Entity> entities = new HashSet<Entity>();
    	//
    	if (playerExecuteSkillCache.getAabbSkillRangeList().isEmpty()) {
			return entities;
		}else {
			playerExecuteSkillCache.getAabbSkillRangeList().forEach(h->{
		        for (Entity entity : serverWorld.getEntitiesWithinAABBExcludingEntity(null, h)) {
		        	entities.add(entity);
		        }
			});
		return entities;
		}
    }

    /**获取缓存的aabb法阵盒
     *
     * @return
     */
    public List<AxisAlignedBB> getCachedAabbSkillRangeList(){
        return playerExecuteSkillCache.getAabbSkillRangeList();
    }


    /**操作技能
     *
     * @param skillName
     * @param optType
     */
    public synchronized void optSkill(String skillName,String optType){
        PlayerDataSkill playerDataSkill= playerDataSkills.getSkillInstanceFromAll(skillName).get();

        if(BaseConst.PLAYER_ADV_TAG__SKILLS_FORGET.equals(optType)){
            if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE)&&playerDataSkills.getSpecialSkillMapping().containsKey(skillName)){
                playerDataSkills.getSpecialSkillMapping().remove(skillName);
            }
            if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD)&&playerDataSkills.getOrdinarySkillMapping().containsKey(skillName)){
                playerDataSkills.getOrdinarySkillMapping().remove(skillName);
            }
        return ;
        }
        if(BaseConst.PLAYER_ADV_TAG__SKILLS_LEARN.equals(optType)){
            //learn start
            if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE)){
                //increse
                if(playerDataSkills.getSpecialSkillMapping().containsKey(skillName)){
                    playerDataSkills.getSpecialSkillMapping().get(skillName)
                            .setSkillLevel(playerDataSkills.getSpecialSkillMapping().get(skillName).getSkillLevel()+1);
                 //learn
                }else{
                    playerDataSkill.setEnable(true);
                    playerDataSkills.getSpecialSkillMapping().put(skillName,playerDataSkill);
                }
            }
            //learn start
            if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD)){
                //increse
                if(playerDataSkills.getOrdinarySkillMapping().containsKey(skillName)){
                    playerDataSkills.getOrdinarySkillMapping().get(skillName)
                            .setSkillLevel(playerDataSkills.getOrdinarySkillMapping().get(skillName).getSkillLevel()+1);
                    //learn
                }else{
                    playerDataSkill.setEnable(true);
                    playerDataSkills.getOrdinarySkillMapping().put(skillName,playerDataSkill);
                }
            }
            return;
            }

        //TOGGLE
        if(BaseConst.PLAYER_ADV_TAG__SKILLS_TOGGLE.equals(optType)){
            if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE)){
                //toggle
                if(playerDataSkills.getSpecialSkillMapping().containsKey(skillName)){
                    playerDataSkills.getSpecialSkillMapping().get(skillName).setEnable(!
                            playerDataSkills.getSpecialSkillMapping().get(skillName).isEnable());
                }
            }
            if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD)){
                //increse
                if(playerDataSkills.getOrdinarySkillMapping().containsKey(skillName)){
                    playerDataSkills.getOrdinarySkillMapping().get(skillName).setEnable(!
                            playerDataSkills.getOrdinarySkillMapping().get(skillName).isEnable());
                }
            }
            return;
        }
    }

    /**技能学习
     *
     * @param skillName
     * @param learnLevel
     * @return
     */
    public synchronized boolean optSkillLearn(String skillName,int learnLevel){
        PlayerDataSkill playerDataSkill= playerDataSkills.getSkillInstanceFromAll(skillName).get();

        //learn start
        if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_SPE)){
            //increse
            if(playerDataSkills.getSpecialSkillMapping().containsKey(skillName)){
                playerDataSkills.getSpecialSkillMapping().get(skillName)
                        .setSkillLevel(playerDataSkills.getSpecialSkillMapping().get(skillName).getSkillLevel()+learnLevel);
                playerDataSkill.setEnable(true);
                //learn
            }else{
                playerDataSkill.setSkillLevel(learnLevel);
                playerDataSkill.setEnable(true);
                playerDataSkills.getSpecialSkillMapping().put(skillName,playerDataSkill);

            }
        }
        //learn start
        if(playerDataSkill.getSkillType().equals(BaseConst.PLAYER_ADV_TAG__SKILLS_ORD)){
            //increse
            if(playerDataSkills.getOrdinarySkillMapping().containsKey(skillName)){
                playerDataSkills.getOrdinarySkillMapping().get(skillName)
                        .setSkillLevel(playerDataSkills.getOrdinarySkillMapping().get(skillName).getSkillLevel()+learnLevel);
                playerDataSkill.setEnable(true);
                //learn
            }else{
                playerDataSkill.setSkillLevel(learnLevel);
                playerDataSkill.setEnable(true);
                playerDataSkills.getOrdinarySkillMapping().put(skillName,playerDataSkill);
            }
        }
        return true;
    }

    /** 所有技能遗忘,返还点数
     *
     * @return
     */
    public synchronized boolean optSkillForgetAll(){
        int totalCountRevert =0;//1级没有技能点
        //技能遗忘
        for (PlayerDataSkill playerDataSkill : playerDataSkills.getFullPlayerDataSkill()) {
            totalCountRevert+=playerDataSkill.getSkillLevel()*playerDataSkill.getUpgradeCount();
            playerDataSkill.setEnable(false);
            playerDataSkill.setSkillLevel(0);
        }
        //返还技能点
        playerDataSkills.setUndistributedSkillPoint(totalCountRevert+playerDataSkills.getUndistributedSkillPoint());
        //取消快捷键映射
        playerDataShortCutTag.getShortCutRelSkill().clear();
        return true;
    }



    /**技能绑定快捷键
     *
     * @param skillName
     * @param shortCutIndex
     * @return
     */
    public synchronized boolean optSkillShortCutBind(String skillName,int shortCutIndex){
        //若传入- 表示清空该技能快捷键绑定
        if ("-".equals(skillName)){
            playerDataShortCutTag.getShortCutRelSkill().remove(shortCutIndex+"");
            //其余表示技能绑定
        }else{
            PlayerDataSkill playerDataSkill= playerDataSkills.getSkillInstanceFromAll(skillName).get();
            playerDataShortCutTag.getShortCutRelSkill().put(shortCutIndex+"",playerDataSkill);
        }
        return true;
    }

    /**技能动画
     *
     * @param skillName
     * @return
     */
    public synchronized boolean skillAnimateCall(String skillName){
        return true;
    }



//    @Deprecated
//    public void increasynchronizedseExp(double exp, EntityPlayer trueSource, EntityLivingBase entityLiving){
//        long expLeft=new BigDecimal(exp).longValue();
//        long currentlevel=playerDataLevelTag.getCurrentLevel();
//        long oldlevel=playerDataLevelTag.getCurrentLevel();
//        long currentexp=playerDataLevelTag.getCurrentExp();
//        boolean isLevelup=false;
//        while (expLeft>0){
//            //levelup
//            long currentmaxexp=new BigDecimal((currentlevel*ConfigHandler.expMinLevel*(1+ConfigHandler.expIncrese))).longValue();
//            if(expLeft+currentexp>currentmaxexp){
//                currentlevel++;
//                expLeft-=(currentmaxexp-currentexp);
//                currentexp=0;
//                isLevelup=true;
//            }else{
//                currentexp+=expLeft;
//                expLeft=0;
//            }
//        }
//        playerDataLevelTag.setCurrentExp(currentexp);
//        if(exp!=0){
//            CmdHelper.execServerSay(new TextComponentTranslation("lineage.expup.msg",trueSource.getName(),entityLiving.getName(),exp));
//        }
//        if(isLevelup){
////            CmdHelper.execServerCommand(trueSource,"　/title @p title {\"text\":\"你升级了！\"}");
//            CmdHelper.execServerSay(new TextComponentTranslation("lineage.levelup.msg",trueSource.getName(),oldlevel,currentlevel));
//            playerDataLevelTag.setCurrentLevel(currentlevel);
//            playerDataLevelTag.updateMaxExp();
//            //update attr
//            playerDataAttributes.setUndistributed(playerDataAttributes.getUndistributed()+ConfigHandler.attrAddPerLevel);
//            //update skill point
//            playerDataSkills.setUndistributedSkillPoint(playerDataSkills.getUndistributedSkillPoint()+ConfigHandler.skillPointAddPerLevel);
//        }
//    }

//    /**玩家升级
//     * 【注意】 该方法升级后剩余经验为 0点
//     * @param updateLevelCount  所需要升级数
//     */
//     public boolean playerLevelUp(int updateLevelCount){
//        //
//        long newLevel=playerDataLevelTag.getCurrentLevel()+updateLevelCount;
//        playerLevelUp(newLevel,0);
//        return true;
//    }

    /**玩家升级 底层实现
     *
     * @param targetLevel 目标升级等级
     * @param leftExp   剩余经验
     */
    public synchronized boolean playerLevelUp(long oldLevel,long targetLevel,long leftExp){
        if (leftExp<=0)leftExp=1;
        //设置当前等级的当前经验
        playerDataLevelTag.setCurrentExp(leftExp);
        //设置当前等级
        playerDataLevelTag.setCurrentLevel(targetLevel);
        //更新当前最大经验值
        playerDataLevelTag.updateMaxExp();
        //更新当前未分配属性点数
        playerDataAttributes.setUndistributed((int) (playerDataAttributes.getUndistributed()+
                        (ConfigHandler.attrAddPerLevel)*(targetLevel-oldLevel)));
        //更新当前未分配技能点数
        playerDataSkills.setUndistributedSkillPoint((int) (playerDataSkills.getUndistributedSkillPoint()+
                        (ConfigHandler.skillPointAddPerLevel)*(targetLevel-oldLevel)));
        return true;
    }

    /**获取玩家快捷键列表
     *
     * @return
     */
    public final PlayerDataShortCutTag getPlayerDataShortCutTag() {
        return playerDataShortCutTag;
    }


    /**检查技能是否处于被执行状态
     *
     * @param skillName
     * @return
     */
    public boolean checkSkillExecuted(String skillName){
        if (playerExecuteSkillCache.getExecuteTimeMap().containsKey(skillName)){
            if (-1L==playerExecuteSkillCache.getExecuteTimeMap().get(skillName))return false;
            return System.currentTimeMillis()>playerExecuteSkillCache.getExecuteTimeMap().get(skillName);
        }
        return false;
    }

    /**更新技能持有状态
     * 
     * @param skillName
     * @return
     */
    public boolean updateSkillHanding(String skillName,boolean state) {
    	playerExecuteSkillCache.getSkillHolding().put(skillName, state);
    	return true;
    }
    /**更新技能持有状态
     *
     * @param skillName
     * @return
     */
    public boolean updateSkillHandingAndSync(String skillName,boolean state,EntityPlayerMP entityPlayerMP){
        updateSkillHanding(skillName,state);
        NetworkHandler.INSTANCE.sendTo(new MessageClientSkillHandingState().write(skillName,state),entityPlayerMP);
        return true;
    }
    
    /**查询当前技能持有状态
     * 
     * @param skillName
     * @return
     */
    public boolean checkSkillHanding(String skillName) {
    	if(playerExecuteSkillCache.getSkillHolding().containsKey(skillName)) {
    		return playerExecuteSkillCache.getSkillHolding().get(skillName);
    	}
    	return false;
    }
    
    /**获取持有技能的技能名
     * 
     * @return
     */
    public String getHoldingSkillName() {
    	Optional<Map.Entry<String,Boolean>> entryOption=playerExecuteSkillCache.getSkillHolding().entrySet().stream().filter(h->{
    		return h.getValue();
    	}).findFirst();
    	if(entryOption.isPresent()) {
    		return entryOption.get().getKey();
    	}
		return null;
    }

    /**检查技能是否处于首次tick检查状态
     *
     * @param skillName
     * @return
     */
    public boolean checkSkillTickOnce(String skillName){
        if (playerExecuteSkillCache.getExecuteOnceTickCheck().containsKey(skillName)){
            return playerExecuteSkillCache.getExecuteOnceTickCheck().get(skillName);
        }
        return false;
    }

    /**设置技能是否处于首次tick状态
     *
     * @param skillName
     * @param status
     */
    public void setSkillTickOnce(String skillName,boolean status){
        playerExecuteSkillCache.getExecuteOnceTickCheck().put(skillName,status);
    }




    /**检查当前技能是否上一执行周期结束
     * @param skillName
     * @return
     */
    public boolean checkOnceTypeSkillAvailable(String skillName){
        if (playerExecuteSkillCache.getExecuteTimeMap().containsKey(skillName)){
            //-1L代表技能已经处于上一周期结束
            if (-1L==playerExecuteSkillCache.getExecuteTimeMap().get(skillName))return true;
            return false;
        }else{
            return true;
        }
    }

    /**检查当前技能是否冷却结束
     *
     * @param skillName
     * @return
     */
    public boolean checkSkillCdAvailable(String skillName){
        if (playerExecuteSkillCache.getExecuteCdMap().containsKey(skillName)){
            //-1L 代表该技能没有CD 随时可以释放
            if (-1L== playerExecuteSkillCache.getExecuteCdMap().get(skillName)){
                return true;
                //当前时间大于cd既定时间, 即可以再次释放
            }else if (System.currentTimeMillis()>playerExecuteSkillCache.getExecuteCdMap().get(skillName)){
                return true;
            //其他条件下认定为cd冷却期,不可触发
            }else{
                return false;
            }
        }else{
            //不在 cd map 中的技能认为未执行过
            return true;
        }
    }

    /**获取指定技能的cd剩余时间
     *
     * @param skillName
     * @return
     */
    public double getSkillCdLeft(String skillName){
        if (playerExecuteSkillCache.getExecuteCdMap().containsKey(skillName)){
            //-1L 代表该技能没有CD 随时可以释放
            if (-1L== playerExecuteSkillCache.getExecuteCdMap().get(skillName)){
                return -1d;
                //当前时间大于cd既定时间, 即可以再次释放
            }else if (System.currentTimeMillis()>playerExecuteSkillCache.getExecuteCdMap().get(skillName)){
                return -1d;
                //其他条件下认定为cd冷却期,不可触发
            }else{
                //计算CD时间
                double cdRemainingSeconds = (playerExecuteSkillCache.getExecuteCdMap().get(skillName) - System.currentTimeMillis()) / 1000.0;

// 如果冷却时间小于0，则显示为0.00
                cdRemainingSeconds = Math.max(0, cdRemainingSeconds);

// 将冷却时间保留两位小数
                return cdRemainingSeconds;
            }
        }else{
            //不在 cd map 中的技能认为未执行过
            return -1d;
        }
    }

    /**设定技能cd
     *
     * @param skillName
     * @param millisecondsCd 毫秒数cd
     * @return
     */
    public boolean setSkillCd(String skillName,long millisecondsCd){
        playerExecuteSkillCache.getExecuteCdMap().put(skillName,millisecondsCd);
        return true;
    }
    /**设定技能cd
     *
     * @param skillName
     * @param millisecondsCd 毫秒数cd
     * @param entityPlayerMP EntityPlayerMP
     * @return
     */
    public boolean setSkillCdAndSync(String skillName,long millisecondsCd,EntityPlayerMP entityPlayerMP){
        long cdavailable = System.currentTimeMillis()+millisecondsCd;
        setSkillCd(skillName,cdavailable);
        //发送技能cd包同步给客户端
        NetworkHandler.INSTANCE.sendTo(new MessageClientSkillCD().write(skillName,cdavailable),entityPlayerMP);
        return true;
    }


    /**检查当前技能是否满足魔法消耗
     *
     * @param needMana
     * @return
     */
    public boolean checkSkillManaAvailable(double needMana){
        if (playerDataManaTag.getCurrentMana()>=needMana)return true;
        return false;
    }



    /**激活技能执行状态
     *
     * @param skillName
     */
    public void turnOnSkillExecuted(String skillName){
        playerExecuteSkillCache.getExecuteTimeMap().put(skillName,System.currentTimeMillis());
    }

    /**激活技能执行状态
     *
     * @param skillName
     */
    public void turnOnSkillExecutedDelay(String skillName,long tick){
        playerExecuteSkillCache.getExecuteTimeMap().put(skillName,System.currentTimeMillis()+tick*50);
    }


    /**关闭技能执行状态
     *
     * @param skillName
     */
    public void turnOffSkillExecuted(String skillName){
        playerExecuteSkillCache.getExecuteTimeMap().put(skillName,-1L);
    }


    /**更新技能AABB盒列表
     * 
     * @param alignedBBs
     */
    public void updateSkillRangeAABBList(List<AxisAlignedBB> alignedBBs) {
    	playerExecuteSkillCache.setAabbSkillRangeList(alignedBBs);
    }

    /**更新技能AABB盒列表
     *
     * @param alignedBBs
     */
    public void updateSkillRangeAABBListAndSync(List<AxisAlignedBB> alignedBBs,EntityPlayerMP entityPlayerMP) {
        playerExecuteSkillCache.setAabbSkillRangeList(alignedBBs);
        NetworkHandler.INSTANCE.sendTo(new MessageClientSkillRange().writeAABBRange(alignedBBs)
                ,entityPlayerMP);
    }




    /**经验提升 底层实现
     *
     * @param leftExp
     * @return
     */
    public synchronized boolean playerExpIncrease(long leftExp){
        if (leftExp<=0)return false;
        //设置当前等级的当前经验
        playerDataLevelTag.setCurrentExp(playerDataLevelTag.getCurrentExp()+leftExp);
        return true;
    }

    /**魔法值变更 底层实现
     *
     * @param manaModify
     * @return
     */
    public synchronized boolean playerManaModify(double manaModify){
        //确保不会为负数或超出上限
        double calculate = playerDataManaTag.getCurrentMana()+manaModify;
        if (calculate>playerDataManaTag.getMaxMana()){
            calculate = playerDataManaTag.getMaxMana();
        }
        if (calculate<0){
            return false;
        }

        playerDataManaTag.setCurrentMana(calculate);
        return true;
    }






    public long getLevel(){
        return playerDataLevelTag.getCurrentLevel();
    }
    public long getCurrentExp(){
        return playerDataLevelTag.getCurrentExp();
    }
    public long getMaxExp(){
        return playerDataLevelTag.getCurrentMaxExp();
    }
    public double getCurrentMana(){
        return playerDataManaTag.getCurrentMana();
    }
    public double getMaxMana(){
        return playerDataManaTag.getMaxMana();
    }
    public double getManaRecover(){
        return playerDataManaTag.getRecoveryOfMana();
    }




    public void tickPlayer(TickEvent.PlayerTickEvent event) {
        forEachEventHandler(h -> h.onPlayerTick(event));
    }

    public void livingFallEvent(LivingFallEvent event) {
        forEachEventHandler(h -> h.onLivingFallEvent(event));
    }



    public void blockDrops(BlockEvent.HarvestDropsEvent event) {
        forEachEventHandler(h -> h.onBlockDrops(event));
    }

    public void mobDrops(LivingDropsEvent event) {
        forEachEventHandler(h -> h.onMobDrops(event));
    }

    public void breakSpeed(PlayerEvent.BreakSpeed event) {
        forEachEventHandler(h -> h.getBreakSpeed(event));
    }

    public void attackMob(LivingHurtEvent event) {
        forEachEventHandler(h -> h.onAttackMob(event));
    }

    public void hurt(LivingHurtEvent event) {
        forEachEventHandler(h -> h.onHurt(event));
    }

    public void rightClickBlock(PlayerInteractEvent.RightClickBlock event) {
        forEachEventHandler(h -> h.onRightClickBlock(event));
    }

    public void enderTeleport(EnderTeleportEvent event) {
        forEachEventHandler(h -> h.onEnderTeleport(event));
    }


    /**
     *
     * @param event
     */
    public void killMob(LivingDeathEvent event) {
        forEachEventHandler(h -> h.onKillMob(event));
    }

    public void rightClickItem(PlayerInteractEvent.RightClickItem event){forEachEventHandler(h->h.onRightClickItem(event) );  }
    public void rightClickItem(PlayerInteractEvent.EntityInteract event){forEachEventHandler(h->h.onRightClickItem(event) );  }
    public void itemUseFinish(LivingEntityUseItemEvent.Finish event){forEachEventHandler(h->h.onItemUseFinish(event));}
    public void playerDead(LivingDeathEvent event){forEachEventHandler(h->h.onPlayerDead(event));}
    public void playerRespawn(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent event){forEachEventHandler(h->h.onPlayerRespawn(event));}
    public void playerLogin(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent event){forEachEventHandler(h->h.onPlayerLogin(event));}

    public void ArrowLoose(EntityJoinWorldEvent event){ forEachEventHandler(h->h.onArrowLoose(event)); }

    public void bowUse(LivingEntityUseItemEvent event){forEachEventHandler(h->{h.onBowUse(event);});}

    public void heal(LivingHealEvent event){forEachEventHandler(h->{h.onHeal(event);});}

    public void playerChangeDimension(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerChangedDimensionEvent event){
        forEachEventHandler(h->{h.onPlayerChangeDimension(event);});
    }
    public void playerClone(net.minecraftforge.event.entity.player.PlayerEvent.Clone event){
        forEachEventHandler(h->{h.onPlayerClone(event);});
    }
    public void skillLevelUp(SkillLevelUpEvent.Post event){
        forEachEventHandlerWithSkillType(h->{
            h.onSkillLevelUp(event);
        },event.getSkillName());
    }
    public void skillShortCutBind(SkillShortCutBindEvent.Post event){
        forEachEventHandlerWithSkillType(h->{
            h.onSkillShortCutBind(event);
        },event.getSkillName());
    }
    //该事件对应的消息触发是 客户端像服务端同步,所以事件为服务端事件
    public void skillAnimateCall(SkillAnimateCallEvent.Post event){
        forEachEventHandlerWithSkillType(h->{
            h.onSkillAnimateCall(event);
        },event.getSkillName());
    }
    
    public void onPlayerSkillHandingOff(String skillName,EntityPlayer entityPlayer) {
        forEachEventHandlerWithSkillType(h->{
            h.onPlayerSkillHandingOff(entityPlayer);
        },skillName);
    }
    
    public void skillRangeSelectedRender(float partialTicks){
    	forEachEventHandler(h->{
    		h.onSkillRangeSelectedRender(partialTicks);
    	});
    }



    /**根据技能名,获取玩家当前技能
     *
     * @param skillName
     * @return
     */
    public Optional<PlayerDataSkill> getPlayerDataSkillByName(String skillName) {
        return playerDataSkills.getSkillInstanceFromAll(skillName);
    }

    /**获取当前用户所有关联技能,包含未学习的
     *
     * @return
     */
    public List<PlayerDataSkill> getAllPlayerDataSkills(){
        return playerDataSkills.getFullPlayerDataSkill();
    }


    /**根据技能快捷键绑定索引获取指定技能
     *
     * @param skillIndex
     * @return
     */
    public Optional<PlayerDataSkill> getPlayerDataSkillBySkillShortCutIndex(int skillIndex) {
        if (playerDataShortCutTag.getShortCutRelSkill().containsKey(skillIndex+"")){
            return Optional.of(playerDataShortCutTag.getShortCutRelSkill().get(skillIndex+""));
        }else{
            return Optional.empty();
        }
    }




    private void forEachEventHandlerWithSkillType(Consumer<IAbilityEventHandler> consumer, String skillTypeName) {
        playerDataSkills.forEachEventHandlerWithType(consumer,skillTypeName);
    }

    private void forEachEventHandler(Consumer<IAbilityEventHandler> consumer) {
        playerDataSkills.forEachEventHandler(consumer);
    }




}
